import 'dart:math';

import 'package:flutter/material.dart';

class ColorSelectPage extends StatefulWidget{

  ColorSelectPage({Key? key,ValueChanged<HSVColor>? onChangeColor});
  ValueChanged<HSVColor>? onChangeColor;

  @override
  State<ColorSelectPage> createState() => _ColorSelectState();
}

class _ColorSelectState extends State<ColorSelectPage>{

  var colors = <Color>[];
  PointerEvent? _event;

  @override
  void initState() {
    super.initState();
    for(int i=0; i<360 ;i++){
      colors.add(HSVColor.fromAHSV(1, i.toDouble(), 1, 1).toColor());
    }
  }

  @override
  Widget build(BuildContext context) {
    return
      Align(
        alignment: Alignment.center,
        child:  Stack(
          children: <Widget>[
            CustomPaint(
              size: Size(300, 160),
              painter: BackgroundColor(colors,16),
            ),
            Listener(
              child: CustomPaint(
                  size: Size(300, 160),
                  painter:CustomColorSelect(_event,16,widget.onChangeColor)
              ),
              onPointerDown: (PointerDownEvent event) => setState(() => _event = event),
              onPointerMove: (PointerMoveEvent event) => setState(() => _event = event),
              onPointerUp: (PointerUpEvent event) => setState(() => _event = event),
            )
          ],
        ) ,
      );
  }
}

class BackgroundColor extends CustomPainter {

  BackgroundColor(this.list,this.radius);
  List<Color> list;
  final double radius;
  var p = Paint();

  @override
  void paint(Canvas canvas, Size size) {
    final Rect rect = Offset(radius, radius) & Size(size.width - 2*radius, size.height - 2*radius);
    final Rect rectA = Offset(0, radius) & Size(size.width, size.height - radius);
    final Rect rect1 = Offset(0, radius) & Size(radius, size.height- 2*radius);
    final Rect rect2 = Offset(size.width - radius, radius) & Size(radius, size.height- 2*radius);
    final Rect rect3 = Offset(0, size.height - radius) & Size(size.width, radius);
    final Rect rect4 = Offset.zero & Size(size.width, radius);

    LinearGradient hue= LinearGradient(
      begin: Alignment.centerLeft,
      end: Alignment.centerRight,
      colors: list,
      tileMode: TileMode.clamp,
    );

    LinearGradient alpha= LinearGradient(
      begin: Alignment.topCenter,
      end: Alignment.bottomCenter,
      colors: [Colors.white,Colors.white.withAlpha(0)],
    );

    p.color = HSVColor.fromAHSV(1, 0, 1, 1).toColor();
    p.style = PaintingStyle.fill;
    canvas.drawRect(rect1, p);
    canvas.drawRect(rect2, p);
    canvas.drawRect(rect3, Paint()..shader = hue.createShader(rect));
    canvas.drawRect(rect, Paint()..shader = hue.createShader(rect));
    canvas.drawRect(rectA, Paint()..shader = alpha.createShader(rect));
    p.color = Colors.white;
    canvas.drawRect(rect4, p);
  }

  @override
  bool shouldRepaint(BackgroundColor oldDelegate) => false;

  @override
  bool shouldRebuildSemantics(BackgroundColor oldDelegate) => false;
}

class CustomColorSelect extends CustomPainter {

  CustomColorSelect(this.event,this.radius, ValueChanged<HSVColor>? onChangeColor);
  PointerEvent? event;
  ValueChanged<HSVColor>? onChangeColor;
  final double radius;
  var p = Paint();

  @override
  void paint(Canvas canvas, Size size) {
    var x = max(min(event?.localPosition.dx??radius, size.width-radius), radius);
    var y = max(min(event?.localPosition.dy??radius, size.height-radius), radius);

    p.color = Colors.white;
    p.style = PaintingStyle.stroke;
    p.strokeWidth = 3;
    canvas.drawCircle(Offset(max(min(event?.localPosition.dx??radius, size.width-radius), radius), max(min(event?.localPosition.dy??radius, size.height-radius), radius)), radius, p);

    HSVColor hsv= HSVColor.fromAHSV(1, (x-radius)/(size.width-radius)*360, (y-radius)/(size.height-radius), 1);

    onChangeColor?.call(hsv);

    p.color = hsv.toColor();
    p.style = PaintingStyle.fill;
    canvas.drawCircle(Offset(x, y), radius, p);
  }

  @override
  bool shouldRepaint(CustomColorSelect oldDelegate) => true;

  @override
  bool shouldRebuildSemantics(CustomColorSelect oldDelegate) => false;
}


